<template>
    <view class="waterfalls-flow">
        <view v-for="(item,index) in data.column" :key="index" class="waterfalls-flow-column" :id="`waterfalls_flow_column_${index+1}`"
            :msg="msg" :style="{'width':w,'margin-left':index==0?0:m}">
            <view class="cell" v-for="(item2,index2) in columnValue(index)" :key="index2"
                :class="['column-value',{'column-value-show':item2.o}]" :style="[s1]" @click.stop="wapperClick(item2)">
                <view class="inner" v-if="data.seat==1">
                    <!-- #ifdef MP-WEIXIN -->
                    <!-- #ifdef VUE2 -->
                    <slot name="slot{{item2.index}}"></slot>
                    <!-- #endif -->
                    <!-- #ifdef VUE3 -->
                    <slot :name="`slot${item2.index}`"></slot>
                    <!-- #endif -->
                    <!-- #endif -->
                    <!-- #ifndef MP-WEIXIN -->
                    <slot v-bind="item2"></slot>
                    <!-- #endif -->
                </view>
                <image :class="['img',{'img-hide':item2[hideImageKey]==true||item2[hideImageKey]==1},{'img-error':!item2[data.imageKey]}]"
                    :src="item2[data.imageKey]" mode="widthFix" @load="imgLoad(item2,index+1)" @error="imgError(item2,index+1)"
                    @click.stop="imageClick(item2)"></image>
                <view class="inner" v-if="data.seat==2">
                    <!-- #ifdef MP-WEIXIN -->
                    <!-- #ifdef VUE2 -->
                    <slot name="slot{{item2.index}}"></slot>
                    <!-- #endif -->
                    <!-- #ifdef VUE3 -->
                    <slot :name="`slot${item2.index}`"></slot>
                    <!-- #endif -->
                    <!-- #endif -->
                    <!-- #ifndef MP-WEIXIN -->
                    <slot v-bind="item2"></slot>
                    <!-- #endif -->
                </view>
            </view>
        </view>
    </view>
</template>
<script>
export default {
    props: {
        value: Array,
        column: {
            // 列的数量
            type: [String, Number],
            default: 2
        },
        maxColumn: {
            // 最大列数
            type: [String, Number],
            default: 5
        },
        columnSpace: {
            // 列之间的间距 百分比
            type: [String, Number],
            default: 2
        },
        imageKey: {
            // 图片key
            type: [String],
            default: 'image'
        },
        hideImageKey: {
            // 隐藏图片key
            type: [String],
            default: 'hide'
        },
        seat: {
            // 文本的位置，1图片之上 2图片之下
            type: [String, Number],
            default: 2
        },
        listStyle: {
            // 单个展示项的样式：eg:{'background':'red'}
            type: Object
        }
    },
    data() {
        return {
            data: {
                list: this.value ? this.value : [],
                column: this.column < 2 ? 2 : this.column,
                columnSpace: this.columnSpace <= 5 ? this.columnSpace : 5,
                imageKey: this.imageKey,
                seat: this.seat
            },
            msg: 0,
            listInitStyle: {
                'border-radius': '16rpx',
                'margin-bottom': '24rpx'
            },
            adds: [], //预置数据
            isLoaded: true,
            curIndex: 0,
            isRefresh: true,
            flag: false,
            refreshDatas: []
        }
    },
    computed: {
        // 计算列宽
        w() {
            const column_rate = `${100 / this.data.column - +this.data.columnSpace}%`
            return column_rate
        },
        // 计算margin
        m() {
            const column_margin = `${
                (100 -
                    (100 / this.data.column - +this.data.columnSpace).toFixed(5) *
                        this.data.column) /
                (this.data.column - 1)
            }%`
            return column_margin
        },
        // list样式
        s1() {
            return { ...this.listInitStyle, ...this.listStyle }
        }
    },
    created() {
        // 初始化
        this.refresh()
    },
    methods: {
        // 预加载图片
        loadImages(idx = 0) {
            let count = 0
            const newList = this.data.list.filter((item, index) => index >= idx)
            for (let i = 0; i < newList.length; i++) {
                // #ifndef APP-PLUS
                uni.getImageInfo({
                    src: `${newList[i][this.imageKey]}.jpg`,
                    complete: (res) => {
                        count++
                        if (count == newList.length) this.initValue(idx)
                    }
                })
                // #endif
                // #ifdef APP-PLUS
                plus.io.getImageInfo({
                    src: `${newList[i][this.imageKey]}.jpg`,
                    complete: (res) => {
                        count++
                        if (count == newList.length) this.initValue(idx)
                    }
                })
                // #endif
            }
        },
        // 刷新
        refresh() {
            if (!this.isLoaded) {
                this.refreshDatas = this.value
                return false
            }
            setTimeout(() => {
                this.refreshDatas = []
                this.isRefresh = true
                this.adds = []
                this.data.list = this.value ? this.value : []
                this.data.column =
                    this.column < 2
                        ? 2
                        : this.column >= this.maxColumn
                        ? this.maxColumn
                        : this.column
                this.data.columnSpace = this.columnSpace <= 5 ? this.columnSpace : 5
                this.data.imageKey = this.imageKey
                this.data.seat = this.seat
                this.curIndex = 0
                // 每列的数据初始化
                for (let i = 1; i <= this.data.column; i++) {
                    this.data[`column_${i}_values`] = []
                    this.msg++
                }
                this.$nextTick(() => {
                    this.initValue(this.curIndex, 'refresh==>')
                })
            }, 1)
        },
        columnValue(index) {
            return this.data[`column_${index + 1}_values`]
        },
        change(newValue) {
            for (let i = 0; i < this.data.list.length; i++) {
                const cv = this.data[`column_${this.data.list[i].column}_values`]
                for (let j = 0; j < cv.length; j++) {
                    if (newValue[i] && i === cv[j].index) {
                        this.data[`column_${this.data.list[i].column}_values`][j] = Object.assign(
                            cv[j],
                            newValue[i]
                        )
                        this.msg++
                        break
                    }
                }
            }
        },
        getMin(a, s) {
            let m = a[0][s]
            let mo = a[0]
            for (var i = a.length - 1; i >= 0; i--) {
                if (a[i][s] < m) {
                    m = a[i][s]
                }
            }
            mo = a.filter((i) => i[s] == m)
            return mo[0]
        },
        // 计算每列的高度
        getMinColumnHeight() {
            return new Promise((resolve) => {
                const heightArr = []
                for (let i = 1; i <= this.data.column; i++) {
                    const query = uni.createSelectorQuery().in(this)
                    query
                        .select(`#waterfalls_flow_column_${i}`)
                        .boundingClientRect((data) => {
                            heightArr.push({ column: i, height: data.height })
                        })
                        .exec(() => {
                            if (this.data.column <= heightArr.length) {
                                resolve(this.getMin(heightArr, 'height'))
                            }
                        })
                }
            })
        },
        async initValue(i, from) {
            this.isLoaded = false
            if (i >= this.data.list.length || this.refreshDatas.length) {
                this.msg++
                this.loaded()
                return false
            }
            const minHeightRes = await this.getMinColumnHeight()
            const c = this.data[`column_${minHeightRes.column}_values`]
            this.data.list[i].column = minHeightRes.column
            c.push({ ...this.data.list[i], cIndex: c.length, index: i, o: 0 })
            this.msg++
        },
        // 图片加载完成
        imgLoad(item, c) {
            const i = item.index
            item.o = 1
            this.$set(
                this.data[`column_${c}_values`],
                item.cIndex,
                JSON.parse(JSON.stringify(item))
            )
            this.initValue(i + 1)
        },
        // 图片加载失败
        imgError(item, c) {
            const i = item.index
            item.o = 1
            item[this.data.imageKey] = null
            this.$set(
                this.data[`column_${c}_values`],
                item.cIndex,
                JSON.parse(JSON.stringify(item))
            )
            this.initValue(i + 1)
        },
        // 渲染结束
        loaded() {
            if (this.refreshDatas.length) {
                this.isLoaded = true
                this.refresh()
                return false
            }
            this.curIndex = this.data.list.length
            if (this.adds.length) {
                this.data.list = this.adds[0]
                this.adds.splice(0, 1)
                this.initValue(this.curIndex)
            } else {
                if (this.data.list.length) this.$emit('loaded')
                this.isLoaded = true
                this.isRefresh = false
            }
        },
        // 单项点击事件
        wapperClick(item) {
            this.$emit('wapperClick', item)
        },
        // 图片点击事件
        imageClick(item) {
            this.$emit('imageClick', item)
        }
    },
    watch: {
        value: {
            deep: true,
            handler(newValue, oldValue) {
                setTimeout(() => {
                    this.$nextTick(() => {
                        if (this.isRefresh) return false
                        if (this.isLoaded) {
                            // if (newValue.length <= this.curIndex) return this.refresh();
                            if (newValue.length <= this.curIndex) return this.change(newValue)
                            this.data.list = newValue
                            this.$nextTick(() => {
                                this.initValue(this.curIndex, 'watch==>')
                            })
                        } else {
                            this.adds.push(newValue)
                        }
                    })
                }, 10)
            }
        },
        column(newValue) {
            this.refresh()
        }
    }
}
</script>
<style lang="scss" scoped>
.waterfalls-flow {
    overflow: hidden;

    &-column {
        float: left;
    }
}
.waterfalls-flow-column {
    border-radius: 16rpx;
    overflow: hidden;
}

.column-value {
    width: 100%;
    font-size: 0;
    overflow: hidden;
    transition: opacity 0.4s;
    opacity: 0;

    &-show {
        opacity: 1;
    }

    .inner {
        font-size: 30rpx;
    }

    .img {
        width: 100%;

        &-hide {
            display: none;
        }

        &-error {
            background: #f2f2f2
                url()
                no-repeat center center;
        }
    }
}
.cell {
    background: rgba($color: #000000, $alpha: 0.5);
    box-shadow: 0px 0px 4px 0px rgba(167, 110, 244, 0.5);
    border-radius: 16rpx;
}
</style>
